<template><div><h2 id="日志" tabindex="-1"><a class="header-anchor" href="#日志"><span>日志</span></a></h2>
<p>Yii 提供了一个强大的日志框架，这个框架具有高度的可定制性和可扩展性。使用这个框架，你可以轻松地记录各种类型的消息，过滤它们，并且将它们收集到不同的标靶中，如文件、数据库、邮件等。</p>
<p>使用 Yii 日志框架涉及下面的几个步骤：</p>
<ul>
<li>在你代码里的各个地方记录 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-messages" target="_blank" rel="noopener noreferrer">日志消息</a>；</li>
<li>在应用配置里通过配置 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 来过滤和导出日志消息；</li>
<li>检查由不同的标靶导出的已过滤的日志消息（例如：<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/tool-debugger.md" target="_blank" rel="noopener noreferrer">Yii debugger</a>）。</li>
</ul>
<p>在这部分，我们主要描述前两个步骤。</p>
<h2 id="日志消息" tabindex="-1"><a class="header-anchor" href="#日志消息"><span>日志消息</span></a></h2>
<p>记录日志消息就跟调用下面的日志方法一样简单：</p>
<ul>
<li>[[Yii::trace()]]：记录一条消息去跟踪一段代码是怎样运行的。这主要在开发的时候使用。</li>
<li>[[Yii::info()]]：记录一条消息来传达一些有用的信息。</li>
<li>[[Yii::warning()]]：记录一个警告消息用来指示一些已经发生的意外。</li>
<li>[[Yii::error()]]：记录一个致命的错误，这个错误应该尽快被检查。</li>
</ul>
<p>这些日志记录方法针对 <em>严重程度</em> 和 <em>类别</em> 来记录日志消息。它们共享相同的函数签名 <code v-pre>function ($message, $category = 'application')</code>，<code v-pre>$message</code> 代表要被记录的日志消息，而 <code v-pre>$category</code> 是日志消息的类别。在下面的示例代码中，在默认的类别 <code v-pre>application</code> 下记录了一条跟踪消息：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token function">trace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'start calculating average revenue'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><blockquote>
<p>Note: 日志消息可以是字符串，也可以是复杂的数据，诸如数组或者对象。<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 的义务是正确处理日志消息。默认情况下，假如一条日志消息不是一个字符串，它将被导出为一个字符串，通过调用 [[yii\helpers\VarDumper::export()]]。</p>
</blockquote>
<p>为了更好地组织和过滤日志消息，我们建议您为每个日志消息指定一个适当的类别。您可以为类别选择一个分层命名方案，这将使得 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 在基于它们的分类来过滤消息变得更加容易。一个简单而高效的命名方案是使用PHP魔术常量 <code v-pre>__METHOD__</code> 作为分类名称。这种方式也在 Yii 框架的核心代码中得到应用，例如，</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token function">trace</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'start calculating average revenue'</span><span class="token punctuation">,</span> <span class="token constant">__METHOD__</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><code v-pre>__METHOD__</code> 常量计算值作为该常量出现的地方的方法名（完全限定的类名前缀）。例如，假如上面那行代码在这个方法内被调用，则它将等于字符串 <code v-pre>'app\controllers\RevenueController::calculate'</code>。</p>
<blockquote>
<p>Note: 上面所描述的日志方法实际上是 <code v-pre>yii\log\Logger</code> 对象（一个通过表达式 <code v-pre>Yii::getLogger()</code> 可访问的单例）的方法 [[yii\log\Logger::log()]] 的一个快捷方式。当足够的消息被记录或者当应用结束时，日志对象将会调用一个 <code v-pre>yii\log\Dispatcher</code> 调度对象将已经记录的日志消息发送到已注册的 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 中。</p>
</blockquote>
<h2 id="日志标靶" tabindex="-1"><a class="header-anchor" href="#日志标靶"><span>日志标靶</span></a></h2>
<p>一个日志标靶是一个 <code v-pre>yii\log\Target</code> 类或者它的子类的实例。它将通过他们的严重层级和类别来过滤日志消息，然后将它们导出到一些媒介中。例如，一个 <code v-pre>yii\log\DbTarget</code> 标靶，导出已经过滤的日志消息到一个数据的表里面，而一个 [[yii\log\EmailTarget]] 标靶，将日志消息导出到指定的邮箱地址里。</p>
<p>在一个应用里，通过配置在应用配置里的 <code v-pre>log</code> <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/structure-application-components.md" target="_blank" rel="noopener noreferrer">应用组件</a>，你可以注册多个日志标靶。就像下面这样：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token comment">// 必须在引导期间加载“log”组件</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token comment">// “log”组件处理带时间戳的消息。 设置 PHP 时区以创建正确的时间戳</span></span>
<span class="line">    <span class="token string single-quoted-string">'timeZone'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'PRC'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\DbTarget'</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'levels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'warning'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\EmailTarget'</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'levels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'categories'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'yii\db\*'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'message'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                       <span class="token string single-quoted-string">'from'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log@example.com'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                       <span class="token string single-quoted-string">'to'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'admin@example.com'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'developer@example.com'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                       <span class="token string single-quoted-string">'subject'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'Database errors at example.com'</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: <code v-pre>log</code> 组件必须在 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-bootstrapping.md" target="_blank" rel="noopener noreferrer">应用引导</a> 期间就被加载，以便于它能够及时调度日志消息到标靶里。这是为什么在上面的代码中，它被列在 <code v-pre>bootstrap</code> 数组中的原因。</p>
</blockquote>
<p>在上面的代码中，在 [[yii\log\Dispatcher::targets]] 属性里有两个日志标靶被注册：</p>
<ul>
<li>第一个标靶选择的是错误和警告层级的消息，并且在数据库表里保存他们；</li>
<li>第二个标靶选择的是错误层级的消息并且是在以 <code v-pre>'yii\db\'</code> 开头的分类下，并且在一个邮件里将它们发送到 <code v-pre>[admin@example.com](mailto:admin@example.com)</code> 和 <code v-pre>[developer@example.com](mailto:developer@example.com)</code>。</li>
</ul>
<p>Yii配备了以下的内建日志标靶。请参考关于这些类的API文档， 并且学习怎样配置和使用他们。</p>
<ul>
<li>[[yii\log\DbTarget]]：在数据库表里存储日志消息。</li>
<li>[[yii\log\EmailTarget]]：发送日志消息到预先指定的邮箱地址。</li>
<li>[[yii\log\FileTarget]]：保存日志消息到文件中。</li>
<li>[[yii\log\SyslogTarget]]：通过调用PHP函数 <code v-pre>syslog()</code> 将日志消息保存到系统日志里。</li>
</ul>
<p>下面，我们将描述所有日志标靶的公共特性。</p>
<h3 id="消息过滤" tabindex="-1"><a class="header-anchor" href="#消息过滤"><span>消息过滤</span></a></h3>
<p>对于每一个日志标靶，你可以配置它的 [[yii\log\Target::levels]] 和 [[yii\log\Target::categories]] 属性来指定哪个消息的严重程度和分类标靶应该处理。</p>
<p>[[yii\log\Target::levels]] 属性是由一个或者若干个以下值组成的数组：</p>
<ul>
<li><code v-pre>error</code>：相应的消息通过 [[Yii::error()]] 被记录。</li>
<li><code v-pre>warning</code>：相应的消息通过 [[Yii::warning()]] 被记录。</li>
<li><code v-pre>info</code>：相应的消息通过 [[Yii::info()]] 被记录。</li>
<li><code v-pre>trace</code>：相应的消息通过 [[Yii::trace()]] 被记录。</li>
<li><code v-pre>profile</code>：相应的消息通过 [[Yii::beginProfile()]] 和 [[Yii::endProfile()]] 被记录。更多细节将在 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#performance-profiling" target="_blank" rel="noopener noreferrer">性能分析</a> 分段解释。</li>
</ul>
<p>如果你没有指定 [[yii\log\Target::levels]] 的属性，那就意味着标靶将处理 <em>任何</em> 严重程度的消息。</p>
<p>[[yii\log\Target::categories]] 属性是一个包含消息分类名称或者模式的数组。一个标靶将只处理那些在这个数组中能够找到对应的分类或者其中一个相匹配的模式的消息。一个分类模式是一个以星号 <code v-pre>*</code> 结尾的分类名前缀。假如一个分类名与分类模式具有相同的前缀，那么该分类名将和分类模式相匹配。例如，<code v-pre>yii\db\Command::execute</code> 和 <code v-pre>yii\db\Command::query</code> 都是作为分类名称运用在 <code v-pre>yii\db\Command</code> 类来记录日志消息的。它们都是匹配模式 <code v-pre>yii\db\*</code>。</p>
<p>假如你没有指定 [[yii\log\Target::categories]] 属性，这意味着标靶将会处理 <em>任何</em> 分类的消息。</p>
<p>除了通过 [[yii\log\Target::categories]] 属性设置白名单分类，你也可以通过 [[yii\log\Target::except]] 属性来设置某些分类作为黑名单。假如一条消息的分类在这个属性中被发现或者是匹配其中一个，那么它将不会在标靶中被处理。</p>
<p>在下面的标靶配置中指明了标靶应该只处理错误和警告消息，当分类的名称匹配 <code v-pre>yii\db\*</code> 或者是 <code v-pre>yii\web\HttpException:*</code> 的时候，但是，除了 <code v-pre>yii\web\HttpException:404</code>。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'levels'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'error'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'warning'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'categories'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'yii\db\*'</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token string single-quoted-string">'yii\web\HttpException:*'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'except'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'yii\web\HttpException:404'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: 当一个 HTTP 异常通过 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-handling-errors.md" target="_blank" rel="noopener noreferrer">错误处理器</a> 被捕获的时候，一个错误消息将以 <code v-pre>yii\web\HttpException:ErrorCode</code> 这样的格式的分类名被记录下来。例如，<code v-pre>yii\web\NotFoundHttpException</code> 将会引发一个分类是 <code v-pre>yii\web\HttpException:404</code> 的错误消息。</p>
</blockquote>
<h3 id="消息格式化" tabindex="-1"><a class="header-anchor" href="#消息格式化"><span>消息格式化</span></a></h3>
<p>日志标靶以某种格式导出过滤过的日志消息。例如，假如你安装一个 <code v-pre>yii\log\FileTarget</code> 类的日志标靶，你应该能找出一个日志消息类似下面的 <code v-pre>runtime/log/app.log</code> 文件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token number">2014</span><span class="token operator">-</span><span class="token number">10</span><span class="token operator">-</span><span class="token number">04</span> <span class="token number">18</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">:</span><span class="token number">15</span> <span class="token punctuation">[</span><span class="token operator">::</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token punctuation">]</span><span class="token punctuation">[</span>trace<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token class-name class-name-fully-qualified static-context">yii<span class="token punctuation">\</span>base<span class="token punctuation">\</span>Module</span><span class="token operator">::</span><span class="token constant">getModule</span><span class="token punctuation">]</span> Loading module<span class="token punctuation">:</span> debug</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>默认情况下，日志消息将被格式化，格式化的方式遵循 [[yii\log\Target::formatMessage()]]：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line">Timestamp <span class="token punctuation">[</span><span class="token constant">IP</span> address<span class="token punctuation">]</span><span class="token punctuation">[</span>User <span class="token constant">ID</span><span class="token punctuation">]</span><span class="token punctuation">[</span>Session <span class="token constant">ID</span><span class="token punctuation">]</span><span class="token punctuation">[</span>Severity Level<span class="token punctuation">]</span><span class="token punctuation">[</span>Category<span class="token punctuation">]</span> Message Text</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>你可以通过配置 [[yii\log\Target::prefix]] 的属性来自定义格式，这个属性是一个 PHP 可调用体返回的自定义消息前缀。例如，下面的代码配置了一个日志标靶的前缀是每个日志消息中当前用户的 ID（IP 地址和 Session ID 被删除是由于隐私的原因）。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'prefix'</span> <span class="token operator">=></span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">has</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'user'</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token class-name return-type">null</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token variable">$userID</span> <span class="token operator">=</span> <span class="token variable">$user</span> <span class="token operator">?</span> <span class="token variable">$user</span><span class="token operator">-></span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token constant boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token string single-quoted-string">'-'</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token string double-quoted-string">"[<span class="token interpolation"><span class="token variable">$userID</span></span>]"</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>除了消息前缀以外，日志标靶也可以追加一些上下文信息到每组日志消息中。默认情况下，这些全局的 PHP 变量的值被包含在：<code v-pre>$_GET</code>，<code v-pre>$_POST</code>，<code v-pre>$_FILES</code>，<code v-pre>$_COOKIE</code>，<code v-pre>$_SESSION</code> 和 <code v-pre>$_SERVER</code> 中。你可以通过配置 [[yii\log\Target::logVars]] 属性适应这个行为，这个属性是你想要通过日志标靶包含的全局变量名称。例如，下面的日志标靶配置指明了只有 <code v-pre>$_SERVER</code> 变量的值将被追加到日志消息中。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'logVars'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'_SERVER'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你可以将 <code v-pre>logVars</code> 配置成一个空数组来完全禁止上下文信息包含。或者假如你想要实现你自己提供上下文信息的方式，你可以重写 [[yii\log\Target::getContextMessage()]] 方法。</p>
<h3 id="消息跟踪级别" tabindex="-1"><a class="header-anchor" href="#消息跟踪级别"><span>消息跟踪级别</span></a></h3>
<p>在开发的时候，通常希望看到每个日志消息来自哪里。这个是能够被实现的，通过配置 <code v-pre>log</code> 组件的 [[yii\log\Dispatcher::traceLevel]] 属性，就像下面这样：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'traceLevel'</span> <span class="token operator">=></span> <span class="token constant">YII_DEBUG</span> <span class="token operator">?</span> <span class="token number">3</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的应用配置设置了 [[yii\log\Dispatcher::traceLevel]] 的层级，假如 <code v-pre>YII_DEBUG</code> 开启则是3，否则是0。这意味着，假如 <code v-pre>YII_DEBUG</code> 开启，每个日志消息在日志消息被记录的时候， 将被追加最多3个调用堆栈层级；假如 <code v-pre>YII_DEBUG</code> 关闭，那么将没有调用堆栈信息被包含。</p>
<blockquote>
<p>Note: 获得调用堆栈信息并不是不重要。因此，你应该只在开发或者调试一个应用的时候使用这个特性。</p>
</blockquote>
<h3 id="消息刷新和导出" tabindex="-1"><a class="header-anchor" href="#消息刷新和导出"><span>消息刷新和导出</span></a></h3>
<p>如上所述，通过 <code v-pre>yii\log\Logger</code> 日志记录器对象，日志消息被保存在一个数组里。为了这个数组的内存消耗，当数组积累了一定数量的日志消息，日志对象每次都将刷新被记录的消息到 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 中。你可以通过配置 <code v-pre>log</code> 组件的 [[yii\log\Dispatcher::flushInterval]] 属性来自定义数量：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'flushInterval'</span> <span class="token operator">=></span> <span class="token number">100</span><span class="token punctuation">,</span>   <span class="token comment">// default is 1000</span></span>
<span class="line">            <span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: 当应用结束的时候，消息刷新也会发生，这样才能确保日志标靶能够接收完整的日志消息。</p>
</blockquote>
<p>当 <code v-pre>yii\log\Logger</code> 日志记录器对象刷新日志消息到 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 的时候，它们并不能立即获取导出的消息。相反，消息导出仅仅在一个日志标靶累积了一定数量的过滤消息的时候才会发生。你可以通过配置个别的 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 的 [[yii\log\Target::exportInterval]] 属性来自定义这个数量，就像下面这样：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'exportInterval'</span> <span class="token operator">=></span> <span class="token number">100</span><span class="token punctuation">,</span>  <span class="token comment">// default is 1000</span></span>
<span class="line"><span class="token punctuation">]</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>因为刷新和导出层级的设置，默认情况下，当你调用 <code v-pre>Yii::trace()</code> 或者任何其他的记录方法，你将不能在日志标靶中立即看到日志消息。这对于一些长期运行的控制台应用来说可能是一个问题。为了让每个日志消息在日志标靶中能够立即出现，你应该设置 [[yii\log\Dispatcher::flushInterval]] 和 [[yii\log\Target::exportInterval]] 都为1，就像下面这样：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'flushInterval'</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">                    <span class="token string single-quoted-string">'exportInterval'</span> <span class="token operator">=></span> <span class="token number">1</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>Note: 频繁的消息刷新和导出将降低你的应用性能。</p>
</blockquote>
<h3 id="切换日志标靶" tabindex="-1"><a class="header-anchor" href="#切换日志标靶"><span>切换日志标靶</span></a></h3>
<p>你可以通过配置 [[yii\log\Target::enabled]] 属性来开启或者禁用日志标靶。你可以通过日志标靶配置去做，或者是在你的代码中放入下面的PHP申明：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Yii</span><span class="token operator">::</span><span class="token variable">$app</span><span class="token operator">-></span><span class="token property">log</span><span class="token operator">-></span><span class="token property">targets</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'file'</span><span class="token punctuation">]</span><span class="token operator">-></span><span class="token property">enabled</span> <span class="token operator">=</span> <span class="token constant boolean">false</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p>上面的代码要求您将标靶命名为 <code v-pre>file</code>，像下面展示的那样，在 <code v-pre>targets</code> 数组中使用字符串键：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">return</span> <span class="token punctuation">[</span></span>
<span class="line">    <span class="token string single-quoted-string">'bootstrap'</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'log'</span><span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token string single-quoted-string">'components'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">        <span class="token string single-quoted-string">'log'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">            <span class="token string single-quoted-string">'targets'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                <span class="token string single-quoted-string">'file'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\FileTarget'</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token string single-quoted-string">'db'</span> <span class="token operator">=></span> <span class="token punctuation">[</span></span>
<span class="line">                    <span class="token string single-quoted-string">'class'</span> <span class="token operator">=></span> <span class="token string single-quoted-string">'yii\log\DbTarget'</span><span class="token punctuation">,</span></span>
<span class="line">                <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">            <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">        <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line">    <span class="token punctuation">]</span><span class="token punctuation">,</span></span>
<span class="line"><span class="token punctuation">]</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>从版本 2.0.13 开始，您可以使用可调用的配置 [[yii\log\Target::enabled]]，以定义是否应启用日志标靶的动态条件。有关示例，请参阅 [[yii\log\Target::setEnabled()]] 文档。</p>
<h3 id="创建新的标靶" tabindex="-1"><a class="header-anchor" href="#创建新的标靶"><span>创建新的标靶</span></a></h3>
<p>创建一个新的日志标靶类非常地简单。你主要需要实现 [[yii\log\Target::export()]] 方法来发送 [[yii\log\Target::messages]] 数组的内容到一个指定的媒体中。你可以调用 [[yii\log\Target::formatMessage()]] 方法去格式化每个消息。更多细节，你可以参考任何一个包含在 Yii 发行版中的日志标靶类。</p>
<blockquote>
<p>Tip: 您可以使用 <a href="https://github.com/samdark/yii2-psr-log-target" target="_blank" rel="noopener noreferrer">PSR 日志标靶扩展</a> 尝试任何兼容 PSR-3 的日志记录器，例如 <a href="https://github.com/Seldaek/monolog" target="_blank" rel="noopener noreferrer">Monolog</a>， 而不是创建自己的日志记录器。</p>
</blockquote>
<h2 id="性能分析" tabindex="-1"><a class="header-anchor" href="#性能分析"><span>性能分析</span></a></h2>
<p>性能分析是一个特殊的消息记录类型，它通常用在测量某段代码块的时间，并且找出性能瓶颈是什么。举个例子，<code v-pre>yii\db\Command</code> 类使用性能分析找出每个数据库查询的时间。</p>
<p>为了使用性能分析，首先确定需要进行分析的代码块。然后像下面这样围住每个代码块：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">beginProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'myBenchmark'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token operator">...</span>code block being profiled<span class="token operator">...</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">endProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'myBenchmark'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这里的 <code v-pre>myBenchmark</code> 代表一个唯一标记来标识一个代码块。之后当你检查分析结果的时候，你将使用这个标记来定位对应的代码块所花费的时间。</p>
<p>对于确保 <code v-pre>beginProfile</code> 和 <code v-pre>endProfile</code> 对能够正确地嵌套，这是很重要的。例如，</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">beginProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'block1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// some code to be profiled</span></span>
<span class="line"></span>
<span class="line">    <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">beginProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'block2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">        <span class="token comment">// some other code to be profiled</span></span>
<span class="line">    <span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">endProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'block2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name class-name-fully-qualified static-context"><span class="token punctuation">\</span>Yii</span><span class="token operator">::</span><span class="token function">endProfile</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'block1'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>假如你漏掉 <code v-pre>\Yii::endProfile('block1')</code> 或者切换了 <code v-pre>\Yii::endProfile('block1')</code> 和 <code v-pre>\Yii::endProfile('block2')</code> 的顺序，那么性能分析将不会工作。</p>
<p>对于每个被分析的代码块，一个带有严重程度为 <code v-pre>profile</code> 的日志消息将被记录。你可以配置一个 <a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/runtime-logging.md#log-targets" target="_blank" rel="noopener noreferrer">日志标靶</a> 去收集这些消息，并且导出他们。<a href="https://github.com/yiisoft/yii2/blob/master/docs/guide-zh-CN/tool-debugger.md" target="_blank" rel="noopener noreferrer">Yii debugger</a> 有一个内建的性能分析面板能够展示分析结果。</p>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


